package com.fa4j.common.base.config;

import com.fa4j.common.base.exception.CommonServerError;
import com.fa4j.common.base.model.ModuleInfo;
import com.fa4j.common.base.util.ModuleUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

import java.util.*;

@Slf4j
@AutoConfiguration
public class CommonBaseAutoConfiguration {

    @Bean
    public List<ModuleInfo> moduleInfoList(ApplicationContext context) {
        long l1 = System.currentTimeMillis();
        Set<String> basePackages = getBasePackages(context);
        Package[] packages = Package.getPackages();
        Map<String, ModuleInfo> packageMap = new HashMap<>();
        Map<Integer, ModuleInfo> moduleCodeMap = new HashMap<>();
        Map<String, ModuleInfo> moduleNameMap = new HashMap<>();

        for (Package p : packages) {
            if (!basePackages.isEmpty() && basePackages.stream().noneMatch(basePackage -> p.getName().startsWith(basePackage))) {
                continue;
            }
            List<ModuleInfo> moduleInfos = ModuleUtil.queryModuleList(p.getName(), 2);
            for (ModuleInfo moduleInfo : moduleInfos) {
                if (!packageMap.containsKey(moduleInfo.getPackageName())) {
                    if (moduleCodeMap.containsKey(moduleInfo.getCode())) {
                        String errMsg = "%s与%s存在相同的模块编码:%s,请到对应的package-info.java修改".formatted(
                                moduleInfo.getPackageName(),
                                moduleCodeMap.get(moduleInfo.getCode()).getPackageName(),
                                moduleInfo.getCode()
                        );
                        throw CommonServerError.INTERNAL_SERVER_ERROR.build(errMsg, null);
                    }
                    if (moduleNameMap.containsKey(moduleInfo.getName())) {
                        String errMsg = "%s与%s存在相同的模块名称:%s,请到对应的package-info.java修改".formatted(
                                moduleInfo.getPackageName(),
                                moduleNameMap.get(moduleInfo.getName()).getPackageName(),
                                moduleInfo.getName()
                        );
                        throw CommonServerError.INTERNAL_SERVER_ERROR.build(errMsg, null);
                    }
                    packageMap.put(moduleInfo.getPackageName(), moduleInfo);
                    moduleCodeMap.put(moduleInfo.getCode(), moduleInfo);
                    moduleNameMap.put(moduleInfo.getName(), moduleInfo);
                    log.debug("识别模块:{}", moduleInfo);
                }
            }
        }
        List<ModuleInfo> moduleInfos = packageMap.values().stream().sorted(Comparator.comparing(ModuleInfo::getCode)).toList();
        long l2 = System.currentTimeMillis();
        log.info("扫码模块完成,模块数量:{}个,耗时:{}ms", packageMap.size(), l2 - l1);
        return moduleInfos;
    }

    private Set<String> getBasePackages(ApplicationContext context) {
        Set<String> basePackages = new HashSet<>();
        context.getBeansWithAnnotation(SpringBootApplication.class).forEach((beanName, bean) -> {
            SpringBootApplication ann = bean.getClass().getAnnotation(SpringBootApplication.class);
            basePackages.add(bean.getClass().getPackageName());
            if (ann != null && ann.scanBasePackages() != null) {
                basePackages.addAll(Arrays.asList(ann.scanBasePackages()));
            }
            if (ann != null && ann.scanBasePackageClasses() != null) {
                for (Class<?> aClass : ann.scanBasePackageClasses()) {
                    basePackages.add(aClass.getPackageName());
                }
            }
        });
        return basePackages;
    }


}
